import 'dart:collection';
import 'dart:convert';
import 'dart:ffi';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:libflutter/net/RDError.dart';
import 'package:libflutter/net/RDResponse.dart';
import 'package:libflutter/net/interceptors/common_interceptor.dart';
import 'package:libflutter/net/interceptors/curl_interceptor.dart';
import 'package:libflutter/net/interceptors/header_interceptor.dart';
import 'package:libflutter/net/interceptors/token_interceptor.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'package:sp_util/sp_util.dart';

///http请求
class RDSerivce {
  final Dio _dio = Dio();

  final TokenInterceptors _tokenInterceptors = TokenInterceptors();
  final HeaderInterceptors _HeaderInterceptors = HeaderInterceptors();
  final CURLInterceptors _CURLInterceptors = CURLInterceptors();
  final PrettyDioLogger _LogInterceptors = PrettyDioLogger(
      requestHeader: true,
      requestBody: true,
      responseBody: true,
      responseHeader: false,
      error: true,
      compact: true,
      maxWidth: 90);

  RDSerivce() {
    _dio.interceptors.add(_tokenInterceptors);
    _dio.interceptors.add(_HeaderInterceptors);
    _dio.interceptors.add(_CURLInterceptors);
  }

  Future<RDResponse> get(url, Map<String, dynamic> queryParams,
      {Map<String, dynamic>? header, void Function()? willRequest}) {
    url = "$url?";
    queryParams.forEach((key, value) {
      url = "$url$key=${value.toString()}&";
    });
    return _netFetch(url.substring(0, url.length - 1), null, header, null, willRequest);
  }

  Future<RDResponse> post(url,
      {Map<String, dynamic>? header,
      Map<String, dynamic>? body,
      Options? option,
      void Function()? willRequest}) async {
    return _netFetch(url, body, header, option ?? Options(method: "post"), willRequest);
  }

  Future<RDResponse> _netFetch<T>(url, params, Map<String, dynamic>? header, Options? option,
      void Function()? willRequest) async {
    Map<String, dynamic> headers = HashMap();
    if (header != null) {
      headers.addAll(header);
    }

    if (option != null) {
      option.headers = headers;
    } else {
      option = Options(method: "get");
      option.headers = headers;
    }
    willRequest?.call();
    Response response;
    try {
      response = await _dio.request(url, data: params, options: option);
    } on DioException catch (e) {
      Response? errorResponse;
      if (e.response != null) {
        errorResponse = e.response;
      } else {
        errorResponse = Response(statusCode: 666, requestOptions: RequestOptions(path: url));
      }
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout ||
          e.type == DioExceptionType.sendTimeout) {
        errorResponse!.statusCode = RDError.NETWORK_TIMEOUT;
      }
      return Future.error(
          RDError(errorResponse!.statusCode!, errorResponse.statusMessage ?? "error"));
    }

    Map<String, dynamic> map;
    try {
      map = response.data;
    } catch (e) {
      map = json.decode(response.data) as Map<String, dynamic>;
    }
    // 获取荣大请求码
    var code = map["code"];
    if (code == null) {
      return Future.error(RDError(RDError.NETWORK_CODE_EMPTY, "Response code is null"));
    }
    switch (code) {
      case RDError.CODE_200:
      case RDError.CODE_0:
        //请求成功, 正确的操作方式
        return Future.value(RDResponse.fromJson(map));
      case RDError.CODE_201:
      case RDError.CODE_2001:
      case RDError.CODE_220:
        //请求成功, 提示
        final msg = map["msg"];
        if (msg != null) {
          Fluttertoast.showToast(msg: msg);
        }
        return Future.value(RDResponse.fromJson(map));
      default:
        return Future.error(RDError(code, map["msg"] ?? "msg is null"));
    }
  }

  void setCommon({required String v, required bool debug}) {
    _dio.interceptors
        .insert(0, CommonInterceptors(SpUtil.getString("select_language", defValue: "zh")!, v));
    if (debug) {
      _dio.interceptors.add(_LogInterceptors);
    } else {
      _dio.interceptors.remove(_LogInterceptors);
    }
  }

  void setTokenAndCrmId({required String token, required String crmId}) {
    _tokenInterceptors.setTokenAndCrmId(token: token, crmId: crmId);
  }

  void setHeaderId({required int orgId, required int projectId, required int userId}) {
    _HeaderInterceptors.setHeaderId(orgId: orgId, projectId: projectId, userId: userId);
  }
}
